﻿using System;
using System.ServiceModel;
using Fluent.Domain;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;

namespace FluentWcfServiceLibrary
{
    /// <summary>
    /// This purpose of this service is to provide a WCF endpoint to test cyclic
    /// reference serialization. There are cases when DataContractSerializer, on
    /// it's own, may be able to serialize/deserialize an object graph but when 
    /// in a WCF context deserialization fails.
    /// 
    /// So, each method is getting an overly eager loaded instance of the object
    /// and passing it over the wire.
    /// 
    /// 
    /// nHibernate 'Session Per Call' or basic Unit Of Work Implementation:
    /// 
    /// The simplest way to get this implemented is to instruct
    /// We want every call to this service to have it's own nHibernate session,
    /// so we tell WCF to spin up a new instance of this class for every request.
    /// We could just open a session in each method, but think about it....
    /// Contrived example:
    /// If i add an order query method and I  want to hang the employee off of it
    /// it would be nice (if i didn't want to actually write the query ;-]) to 
    /// be able to call GetEmployee(). If I don't implement UOW in some fashion
    /// we are going to have a mess on our hands.
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class Service1 : IService1, IDisposable
    {
        private const string ConnectionStringKey = "Northwind";


        /// <summary>
        /// Building this factory is expensive and need be done but once in the static constructor.
        /// </summary>
        private static readonly ISessionFactory Factory;

        /// <summary>
        /// a simple Unit Of Work implementation: 
        /// DO NOT DO THIS AT WORK OR YOU WILL BE FIRED! ;-)
        /// 
        /// ensure each call to this service instantiates a new Service1 and provide a common session from the
        /// default instance constructor.
        /// </summary>
        private ISession _session;


        static Service1()
        {
            Factory = Fluently.Configure()
                .Database(
                MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey(ConnectionStringKey)))
                .Mappings(m => m.FluentMappings.AddFromAssembly(typeof (Service1).Assembly))
                .BuildSessionFactory();
        }

        public Service1()
        {
            _session = Factory.OpenSession();
        }

        #region IDisposable Members

        /// <summary>
        /// You are responsible for deterministically flushing and or commiting. 
        /// Dispose is just closing and nulling the session.
        /// </summary>
        public void Dispose()
        {
            if (_session != null)
            {
                _session.Close();
                _session.Dispose();
                _session = null;
            }
        }

        #endregion

        #region IService1 Members

        public Orders GetOrder(int id)
        {
            var order = _session.Get<Orders>(id);
            return order;
        }

        public Categories GetCategories(int id)
        {
            var result = _session.Get<Categories>(id);
            return result;
        }

        public Customers GetCustomers(string id)
        {
            var result = _session.Get<Customers>(id);
            return result;
        }

        public Shippers GetShippers(int id)
        {
            var result = _session.Get<Shippers>(id);
            return result;
        }

        public Suppliers GetSuppliers(int id)
        {
            var result = _session.Get<Suppliers>(id);
            return result;
        }

        public Products GetProducts(int id)
        {
            var result = _session.Get<Products>(id);
            return result;
        }

        public Order_Details GetOrder_Details(int orderId, int productId)
        {
            var result = _session.Get<Order_Details>(new Order_Details(orderId, productId));
            return result;
        }

        public CustomerCustomerDemo GetCustomerCustomerDemo(string customerId, string customerTypeId)
        {
            var result = _session.Get<CustomerCustomerDemo>(new CustomerCustomerDemo(customerId, customerTypeId));
            return result;
        }

        public CustomerDemographics GetCustomerDemographics(string customerTypeId)
        {
            var result = _session.Get<CustomerDemographics>(customerTypeId);
            return result;
        }

        public Region GetRegion(int id)
        {
            var result = _session.Get<Region>(id);
            return result;
        }

        public Territories GetTerritories(string id)
        {
            var result = _session.Get<Territories>(id);
            return result;
        }

        public EmployeeTerritories GetEmployeeTerritories(int employeeId, string territoryId)
        {
            var result = _session.Get<EmployeeTerritories>(new EmployeeTerritories(employeeId, territoryId));
            return result;
        }

        public Employees GetEmployees(int id)
        {
            var result = _session.Get<Employees>(id);
            return result;
        }

        #endregion
 
    }
}